﻿namespace MyCompany.ViewModels {
	using System;
	using System.Collections.ObjectModel;
	using System.Threading;

	using MyCompany.Core;

	using SolidMvvm;

	using SolidMvvmInterfaces;

	public class MyApplicationViewModel :  ApplicationViewModelBase, IMessageReporter {
		bool isLogViewerVisible = true;

		LogViewModel logViewModel;

		string outputText;

		bool simulateCleanupErrorUponExit;

		public MyApplicationViewModel(IApplicationContext applicationContext, ObservableCollection<ISnapInPoint> leftStatusBarSnapInPoints, ObservableCollection<ISnapInPoint> centerStatusBarSnapInPoints, ObservableCollection<ISnapInPoint> rightStatusBarSnapInPoints, IMessageReporter messageReporter, ApplicationExitRequestedDelegate applicationExitRequestedDelegate) : base(applicationContext, messageReporter, applicationExitRequestedDelegate) {
			try {
				LeftStatusBarSnapInPoints = leftStatusBarSnapInPoints;
				CenterStatusBarSnapInPoints = centerStatusBarSnapInPoints;
				RightStatusBarSnapInPoints = rightStatusBarSnapInPoints;

				leftStatusBarSnapInPoints.Add(new SnapInPoint { Content = "Left" });
				leftStatusBarSnapInPoints.Add(new SnapInPoint { Content = "Left2" });
				centerStatusBarSnapInPoints.Add(new SnapInPoint { Content = "Center" });
				centerStatusBarSnapInPoints.Add(new SnapInPoint { Content = "Center" });
				rightStatusBarSnapInPoints.Add(new SnapInPoint { Content = "Right" });
				rightStatusBarSnapInPoints.Add(new SnapInPoint { Content = "Right" });

				ReportMessage(applicationContext.ApplicationName + " started.", null, MessageType.Console);
			}
			catch (Exception exception) {
				SuppressCanClose();
				Cleaner.CleanConstructor(this, exception);
			}
		}

		public IMyApplicationViewModelObserver MyApplicationViewModelObserver { get; set; }

		public ObservableCollection<ISnapInPoint> LeftStatusBarSnapInPoints { get; private set; }

		public ObservableCollection<ISnapInPoint> CenterStatusBarSnapInPoints { get; private set; }

		public ObservableCollection<ISnapInPoint> RightStatusBarSnapInPoints { get; private set; }

		public bool _IsLogViewerVisible
		{
			get
			{
				return isLogViewerVisible;
			}
			set
			{
				if (isLogViewerVisible == value)
					return;

				isLogViewerVisible = value;
				RaisePropertyChanged(() => _IsLogViewerVisible);
			}
		}

		public string _OutputText
		{
			get
			{
				return outputText;
			}
			set
			{
				if (outputText == value)
					return;

				outputText = value;
				RaisePropertyChanged(() => _OutputText);
			}
		}

		public LogViewModel _LogViewModel
		{
			get
			{
				return logViewModel;
			}
			set
			{
				if (logViewModel == value)
					return;

				logViewModel = value;
				RaisePropertyChanged(() => _LogViewModel);
			}
		}

		public void ReportMessage(string publicMessage, string privateMessageOrNull, MessageType messageType) {
			_OutputText += DateTime.Now.ToString("HH:mm:ss.fff") + " " + publicMessage + "\n";
			ApplicationContext.ReportMessage(publicMessage, privateMessageOrNull, messageType);
		}

		public void _ForceUnhandledException() {
			// Simulate an operation that throws an exception here.
			throw new GeneralException("Exception message to show to user here.", "More information that is logged, but not shown to the user.");
		}

		public void _ForceHandledException() {
			try {
				// Simulate an operation that throws an exception here.
				throw new GeneralException("Exception message to show to user here.", "More information that is logged, but not shown to the user.");
			}
			catch (Exception exception) {
				ReportMessage(exception.Message, exception.ToString(), MessageType.Display);
			}
		}

		public void _RequestApplicationExit() {
			// Exit cleanly without exceptions.
			simulateCleanupErrorUponExit = false;
			ApplicationExitRequested(this);
		}

		public void _RequestApplicationExitWithSimulatedCleanupException() {
			// Simulate a problem during cleanup such as trouble closing a device/database/file/etc.
			simulateCleanupErrorUponExit = true;
			ApplicationExitRequested(this);
		}

		//public event ShowLogDialogDelegate _ShowLogDialog;

		//public event HideLogDialogDelegate _HideLogDialog;

		//public event ShowMessageBoxDelegate _ShowMessageBox;

		//public event ShowPromptToSaveWorkDelegate /;

		public override void Dispose() {
			using (var cleaner = new Cleaner()) {
				cleaner.CleanWithLambda(() => {
					if (simulateCleanupErrorUponExit)
						throw new GeneralException("A problem happened when cleaning up.", null);
				});

				cleaner.CleanWithLambda(() => base.Dispose());

				LeftStatusBarSnapInPoints = null;
				CenterStatusBarSnapInPoints = null;
				RightStatusBarSnapInPoints = null;
			}
		}

		// If you derive from CloseableViewModelBase, then uncomment this.
		public override bool CanClose() {
			if (MyApplicationViewModelObserver != null && MyApplicationViewModelObserver.ShowPromptToConfirmApplicationClose())
				return base.CanClose();

			return false;
		}

		public void _ShowMessageBoxRequested() {
			MyApplicationViewModelObserver?.ShowMessageBoxDelegate();
		}

		public void _ShowLogDialogRequested() {
			_LogViewModel = new LogViewModel(ApplicationContext.GetLogFileAsString(), MessageReporter, LogViewModel_OkRequestedDelegate);
			MyApplicationViewModelObserver?.ShowLogDialogDelegate();
		}

		void CloseLogDialog() {
			MyApplicationViewModelObserver.HideLogDialogDelegate();

			var logViewModelToDispose = _LogViewModel;
			_LogViewModel = null;
			logViewModelToDispose.Dispose();
		}

		public void _CloseLogDialogRequested() {
			CloseLogDialog();
		}

		void LogViewModel_OkRequestedDelegate(LogViewModel sender) {
			CloseLogDialog();
		}

		public void _ShowWaitCursor() {
			// Automatically turn on a wait cursor and then restore it upon Dipose at the end of the 'using' block.
			using (new WaitStateIndicator())
				Thread.Sleep(3000);
		}

		public void _ToggleLogViewer() {
			_IsLogViewerVisible = !_IsLogViewerVisible;
		}

		public void _AboutBox() {
			ApplicationContext.ShowAboutBox();
		}

		public interface IMyApplicationViewModelObserver : IViewModelObserver {
			void HideLogDialogDelegate();

			void ShowLogDialogDelegate();

			void ShowMessageBoxDelegate();

			bool ShowPromptToConfirmApplicationClose();
		}
	}
}
